<?php

namespace App\Http\Controllers\Api\V1;

use App\Models\SystemOption;
use App\Models\YzToken;
use Illuminate\Http\Request;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use App\Models\Token;
use App\Models\Authorization;
class AuthController extends BaseController
{
    private $result = array('code' => '10000', 'message' => '系统服务异常', 'data' => array());

    /**
     * @api {post} /authorizations 1. 登录（创建一个token create a token)
     * @apiDescription 登录（创建一个token create a token)
     * @apiGroup Auth
     * @apiPermission none
     * @apiParam {String{..11}} mobile  手机号码
     * @apiParam {String{6..20}} password  密码
     * @apiParam {Number{1,2}} platform  平台：1 Android，2 iOS
     * @apiParam {String{1..50}} device_type  设备具体类型 eg：iPhone 6 plus, Mi 5 plus
     * @apiParam {String{1..200}} device_id  设备唯一id eg：861206031257240
     * @apiParam {String{1..20}} system_version  系统版本 eg：6.0，10.1.1
     * @apiVersion 0.1.0
     * @apiHeaderExample {json} Header-Example:
     *      {
     *          "Accept": "application/vnd.argo.v1+json"
     *      }
     * @apiSuccessExample {json} Success-Response:
     *      HTTP/1.1 200 OK
     *      {
     *          "code": 200,
     *          "message": "登录成功",
     *          "data": {
     *              "id": 10000,
     *              "mobile": "18511891205",
     *              "nickname": "wahaha",
     *              "avatar": null,
     *              "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vdGVzdC5hcGkua291a291bG9vbmcuY29tL2F1dGhvcml6YXRpb25zIiwiaWF0IjoxNDg3MjI4MzE1LCJleHAiOjE0ODc0NDQzMTUsIm5iZiI6MTQ4NzIyODMxNSwianRpIjoiRVJaU3dqRmZOTmp6UzlrRSIsInN1YiI6MTAwMDB9.Kqey90ADZ2Cyko07E4T2qgOKiMbydOUtz_SmwX9sD7E",
     *              "expired_at": "2017-02-18 18:58:35",
     *              "refresh_expired_at": "2017-03-02 06:58:35"
     *          }
     *      }
     * @apiErrorExample {json} Error-Response:
     *      HTTP/1.1 200 OK
     *      {
     *          "code": 20005,
     *          "message": "密码格式不正确"
     *          "data": []
     *      }
     */
    public function store(Request $request)
    {
        // 自定义验证规则
        $rules = [
            'mobile'            => 'required|regex:/^1[34578][0-9]{9}$/',
            'password'          => 'required|min:6|max:20|regex:/^[a-zA-Z0-9~!@#$%^&*()_]{6,20}$/i',
            'platform'          => 'required|numeric|in:1,2',
            'device_type'       => 'required|string|max:50',
            'device_id'         => 'required|string|max:200',
            'system_version'    => 'required|string|max:20'
        ];
        // 自定义提示
        $messages = [
            'mobile.required'           => ['code' => 20001, 'message' => ':attribute 不能为空.', 'data' => []],
            'mobile.regex'              => ['code' => 20002, 'message' => ':attribute 格式不正确.', 'data' => []],
            'password.required'         => ['code' => 20003, 'message' => ':attribute 不能为空.', 'data' => []],
            'password.min'              => ['code' => 20004, 'message' => ':attribute 长度为6到20个字符之间.', 'data' => []],
            'password.max'              => ['code' => 20004, 'message' => ':attribute 长度为6到20个字符之间.', 'data' => []],
            'password.regex'            => ['code' => 20005, 'message' => ':attribute 格式不正确.', 'data' => []],
            'platform.required'         => ['code' => 20007, 'message' => ':attribute 不能为空.', 'data' => []],
            'platform.numeric'          => ['code' => 20008, 'message' => ':attribute 必须是一个数字.', 'data' => []],
            'platform.in'               => ['code' => 20009, 'message' => ':attribute 必须是1或者2其中一个.', 'data' => []],
            'device_type.required'      => ['code' => 20010, 'message' => ':attribute 不能为空.', 'data' => []],
            'device_type.string'        => ['code' => 20011, 'message' => ':attribute 必须是一个字符串.', 'data' => []],
            'device_type.max'           => ['code' => 20012, 'message' => ':attribute 不能大于50个字符.', 'data' => []],
            'device_id.required'        => ['code' => 20013, 'message' => ':attribute 不能为空.', 'data' => []],
            'device_id.string'          => ['code' => 20014, 'message' => ':attribute 必须是一个字符串.', 'data' => []],
            'device_id.max'             => ['code' => 20015, 'message' => ':attribute 不能大于200个字符.', 'data' => []],
            'system_version.required'   => ['code' => 20016, 'message' => ':attribute 不能为空.', 'data' => []],
            'system_version.string'     => ['code' => 20017, 'message' => ':attribute 必须是一个字符串.', 'data' => []],
            'system_version.max'        => ['code' => 20018, 'message' => ':attribute 不能大于20个字符.', 'data' => []]
        ];
        $validator = \Validator::make($request->all(), $rules, $messages);

        if ($validator->fails()) {
            $messages = $validator->errors()->toArray();
            foreach ($messages as $value) {
                $this->result['code'] = $value[0]['code'];
                $this->result['message'] = $value[0]['message'];
                break;
            }
            return $this->response->array($this->result);
        }

        $flag = $request->get('platform') == 1 ? 'Android' : 'IOS';
        $credentials = $request->only('mobile', 'password');

        if(!User::where('mobile',$credentials['mobile'])->first()){
            $this->result['code'] = 20020;
            $this->result['message'] = '该手机号未注册';
            return $this->response->array($this->result);
        }
        // 验证失败返回403
        if (! $token = \Auth::attempt($credentials)) {
            //$this->response->errorForbidden(trans('auth.incorrect'));
            $this->result['code'] = 20006;
            $this->result['message'] = '手机号码或密码错误';
            return $this->response->array($this->result);
        }

        // 获取用户实例
        $user = User::where('mobile', $request->get('mobile'))->select('id', 'mobile', 'platform', 'device_type', 'device_id', 'system_version', 'state')->first();

        // 获取token信息
        $tokenInfo = Token::where('uid', $user->id)->select('id', 'token', 'expired_at', 'refresh_expired_at')->first();

        // 判断token是否过期
        $nowTime = Carbon::now()->toDateTimeString();

        if (strtotime($nowTime) > strtotime($user->expired_at)) {
            $authorization = new Authorization($token);
            $authorizationArr = $authorization->toArray();

            $token = $authorizationArr['token'];
            $expired_at = $authorizationArr['expired_at'];
            $refresh_expired_at = $authorizationArr['refresh_expired_at'];

            // 更新token信息入库
            Token::where('uid', $user->id)->update(['token' => $token, 'expired_at' => $expired_at, 'refresh_expired_at' => $refresh_expired_at]);
        } else {
            $token      = $tokenInfo->token;
            $expired_at = $tokenInfo->expired_at;
            $refresh_expired_at = $tokenInfo->refresh_expired_at;
        }

        // 获取用户信息
        $data = User::where('id', $user->id)->select('id', 'mobile', 'nickname', 'avatar')->first();
        $this->result['data'] = $data->toArray();

        $this->result['code'] = 200;
        $this->result['message'] = '登陆成功';
        $this->result['data']['token_id']   = $tokenInfo->id;
        $this->result['data']['token']      = $token;
        $this->result['data']['expired_at'] = $expired_at;
        $this->result['data']['refresh_expired_at'] = $refresh_expired_at;

        return $this->response->array($this->result);
    }

    /**
     * @api {put} /authorizations/current 2. 刷新token(refresh token)
     * @apiDescription 刷新token(refresh token)
     * 客户端用户登录成功后会得到 token 的两个有效期：expired_at 和 refresh_expired_at，客户端根据这个过期时间调用刷新token接口，或者在请求结果为401的时候调用刷新token接口
     * @apiGroup Auth
     * @apiPermission JWT
     * @apiVersion 0.1.0
     * @apiHeader {String} Authorization 用户旧的jwt-token, value以Bearer开头
     * @apiParam string $token_id
     * @apiHeaderExample {json} Header-Example:
     *     {
     *          "Accept": "application/vnd.argo.v1+json",
     *          "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vdGVzdC5hcGkua291a291bG9vbmcuY29tL2F1dGhvcml6YXRpb25zIiwiaWF0IjoxNDg2NTI0MzgyLCJleHAiOjE0ODY3NDAzODIsIm5iZiI6MTQ4NjUyNDM4MiwianRpIjoiYjhYcEhuYndBeWVDeWIzZyIsInN1YiI6MTJ9.p3553WGzqnQCbO5MhZP4wgnyiNgb1MGJMP9Yelso-TE"
     *     }
     * @apiSuccessExample {json} Success-Response:
     *      HTTP/1.1 200 OK
     *      {
     *          "code": 200,
     *          "message": "刷新token成功",
     *          "data": {
     *              "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vdGVzdC5hcGkua291a291bG9vbmcuY29tL2F1dGhvcml6YXRpb25zL2N1cnJlbnQiLCJpYXQiOjE0ODY1MjQzODIsImV4cCI6MTQ4Njc0MDY5MSwibmJmIjoxNDg2NTI0NjkxLCJqdGkiOiJleUdtUWRtNm1FbFFsbjNuIiwic3ViIjoxMn0.KdzAKHHkTwGtA6TEq-YvBA0t1YHmx8zj1EsjvihAGyQ",
     *              "expired_at": "2017-02-10 15:31:31",
     *              "refresh_expired_at": "2017-02-22 03:31:31"
     *          }
     *      }
     */
    public function update($token_id)
    {
        $authorization = new Authorization(\Auth::refresh());
        $authorizationArr = $authorization->toArray();

        $token = $authorizationArr['token'];
        $expired_at = $authorizationArr['expired_at'];
        $refresh_expired_at = $authorizationArr['refresh_expired_at'];

        // 更新token信息入库
        Token::where('id', $token_id)->update(['token' => $token, 'expired_at' => $expired_at, 'refresh_expired_at' => $refresh_expired_at]);

        // check token
        // same with \Auth::requireToken()->checkOrFail();
        $this->result['code'] = 200;
        $this->result['message'] = '刷新成功';
        $this->result['data'] = [
            'token_id' => $token_id,
            'token' => $token,
            'expired_at' => $expired_at,
            'refresh_expired_at' => $refresh_expired_at,
        ];

        return $this->response->array($this->result);
    }

    /**
     * @api {delete} /authorizations/current 3. 删除当前token (delete current token)
     * @apiDescription 删除当前token (delete current token)
     * @apiGroup Auth
     * @apiPermission jwt
     * @apiVersion 0.1.0
     * @apiHeaderExample {json} Header-Example:
     *      {
     *          "Accept": "application/vnd.koukouloong.v1+json"
     *      }
     * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     *      {
     *          "code": 200,
     *          "message": "刷新token成功",
     *          "data": []
     *      }
     */
    public function destroy()
    {
        \Auth::logout();

        $this->result['code'] = 200;
        $this->result['message'] = '删除token成功';
        $this->result['data'] = [];

        return $this->response->array($this->result);
    }

    /**
     * @api {get} /authorizations/logout 4. 退出登录 (logout)
     * @apiDescription 退出登录 (logout)
     * @apiGroup Auth
     * @apiPermission jwt
     * @apiVersion 0.1.0
     * @apiHeaderExample {json} Header-Example:
     *      {
     *          "Accept": "application/vnd.argo.v1+json",
     *          "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vdGVzdC5hcGkua291a291bG9vbmcuY29tL2F1dGhvcml6YXRpb25zIiwiaWF0IjoxNDg2NTI0MzgyLCJleHAiOjE0ODY3NDAzODIsIm5iZiI6MTQ4NjUyNDM4MiwianRpIjoiYjhYcEhuYndBeWVDeWIzZyIsInN1YiI6MTJ9.p3553WGzqnQCbO5MhZP4wgnyiNgb1MGJMP9Yelso-TE"
     *      }
     * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     *      {
     *          "code": 200,
     *          "message": "退出登录成功",
     *          "data": []
     *      }
     */
    public function logout()
    {
        $user = $this->user();
        Token::where('uid',$user->id)->update(['expired_at'=>'1970-01-01']);
        $this->destroy();
        $this->result['code'] = 200;
        $this->result['message'] = '退出登录成功';
        $this->result['data'] = [];

        return $this->response->array($this->result);
    }


    /**
     * @api {post} /api/checkcode 4. 校验验证码 (checkCode)
     * @apiDescription 校验验证码 (checkCode)
     * @apiGroup Auth
     * @apiPermission jwt
     * @apiVersion 0.1.0
     * @apiSuccessExample {json} Success-Response:
     *     HTTP/1.1 200 OK
     *      {
     *          "code": 200,
     *          "message": "校验验证码成功",
     *          "data": []
     *      }
     * @apiErrorExample {json} Error-Response:
     *      HTTP/1.1 200 OK
     *      {
     *          "code": 21101,
     *          "message": "手机号不能为空"
     *          "data": []
     *      }
     */
    public function checkCode(Request $request){
        $rules =[
               'mobile'  => 'required|regex:/^1[34578][0-9]{9}$/',
               'code'    =>'required|min:6',
               'type'    =>'required|numeric|in:1,2'
        ];
        $messages = [
            'mobile.required' => ['code' => 21101, 'message' => ':attribute 不能为空.', 'data' => []],
            'mobile.regex'    => ['code' => 21102, 'message' => ':attribute 格式不正确.', 'data' => []],
            'code.required'   => ['code' => 21103, 'message' => ':attribute 不能为空.', 'data' => []],
            'code.min'        => ['code' => 21104, 'message' => ':attribute 必须为6位.', 'data' => []],
            'type.required'   => ['code' => 21105, 'message' => ':attribute 不能为空.', 'data' => []],
            'type.numeric'    => ['code' => 21106, 'message' => ':attribute 必须是一个数字.', 'data' => []],
            'type.in'         => ['code' => 21107, 'message' => ':attribute 必须是1或者2其中一个.', 'data' => []]
        ];
        $validator = \Validator::make($inputValue = $request->all(), $rules, $messages);
        if ($validator->fails()) {
            $messages = $validator->errors()->toArray();
            foreach ($messages as $value) {
                $this->result['code'] = (int)$value[0]['code'];
                $this->result['message'] = $value[0]['message'];
                break;
            }
            return $this->response->array($this->result);
        }
        $mobile = $inputValue['mobile'];
        $code   = $inputValue['code'];
        $type   = $inputValue['type'];
        $check_code = Redis::hGetAll($type.'_' . $mobile);
        // 判断对应的redis存不存在
        if (empty($check_code)) {
            //return $this->response->errorBadRequest(trans('auth.captcha'));
            $this->result['code'] = 21108;
            $this->result['message'] = '验证码已失效，请重新获取验证码';
            return $this->response->array($this->result);
        }

        // 判断验证码
        if ($check_code['rand_code'] != $code) {
            //return $this->response->errorBadRequest(trans('auth.captcha'));
            $this->result['code'] = 21109;
            $this->result['message'] = '验证码错误';
            return $this->response->array($this->result);
        }

        // 判断有无过期
        if ($check_code['time'] + 300 < time()) {
            //return $this->response->errorBadRequest(trans('auth.overtime'));
            $this->result['code'] = 21110;
            $this->result['message'] = '验证码超时，请重新获取验证码';
            return $this->response->array($this->result);
        }

        // 判断手机号与验证码符不符合
        if ($mobile . '_' . $code != $check_code['mobile'] . '_' . $check_code['rand_code']) {
            //return $this->response->errorBadRequest(trans('auth.difference'));
            $this->result['code'] = 21111;
            $this->result['message'] = '手机号码与验证码不符';
            return $this->response->array($this->result);
        }

        $this->result['code']    = '200';
        $this->result['message'] = '验证码验证成功';
        $this->result['data']    = [];
        return $this->response->array($this->result);
    }

    /**
     * 获取系统配置信息，建议app启动时请求该接口
     * @param Request $request
     * @return mixed
     */
    public function getSystemOption(Request $request){
        Log::debug(json_encode($request->header()));
        $options = SystemOption::all();
        $data    = [];
        foreach ($options  as $option){
            switch ($option->name){
                case 'start_page':
                    $data['start_page'] = $option->value;
                    break;
                case 'android_version':
                    $data['android']['version'] = $option->value;
                    break;
                case 'android_code':
                    $data['android']['code']    = $option->value;
                    break;
                case 'android_url':
                    $data['android']['url']    = $option->value;
                    break;
                case 'ios_version':
                    $data['ios']['version']    = $option->value;
                    break;
                case 'ios_code':
                    $data['ios']['code']    = $option->value;
                    break;
                case 'ios_url':
                    $data['ios']['url']        = $option->value;
                    break;
                case 'youzan':
                    $data['youzan']            = empty($youZan=json_decode($option->value,true))?[]:$youZan;
                    break;

            }
        }
        $this->result['code']    = '200';
        $this->result['message'] = 'ok';
        $this->result['data']    = $data;

        return $this->response->array($this->result);
    }
}
